package com.pigcloud.sop.gatewaycommon.gateway.loadbalancer;

import com.alibaba.cloud.nacos.NacosServiceInstance;
import com.pigcloud.sop.gatewaycommon.bean.SopConstants;
import com.pigcloud.sop.gatewaycommon.gateway.ServerWebExchangeUtil;
import com.pigcloud.sop.gatewaycommon.param.ApiParam;
import com.pigcloud.sop.gatewaycommon.util.LoadBalanceUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.EmptyResponse;
import org.springframework.web.server.ServerWebExchange;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 描述信息:  开发平台负载均衡
 *
 * @param
 * @return
 * @Author wangfm
 * @Date: 2024/1/2
 */
@Slf4j
@AllArgsConstructor
public class SopLoadBalancerClient implements SopLoadBalancer<ServerWebExchange> {
    private final DiscoveryClient discoveryClient;


    /**
     * 根据serviceId 筛选可用服务
     *
     * @param serviceId 服务ID
     * @param request   当前请求
     * @return
     */
    @Override
    public ServiceInstance choose(String serviceId, ServerWebExchange request) {
        List<ServiceInstance> serviceInstances = discoveryClient.getInstances(serviceId);
        if (CollectionUtils.isEmpty(serviceInstances)) {
            log.warn("注册中心无可用实例 {}", serviceId);
            return new EmptyResponse().getServer();
        }
        String clientIp = request.getRequest().getHeaders().getFirst(SopConstants.CLIENT_IP);
        // 存放预发服务器
        List<ServiceInstance> preServers = new ArrayList<>(4);
        // 存放灰度发布服务器
        List<ServiceInstance> grayServers = new ArrayList<>(4);
        // 存放非预发服务器
        List<ServiceInstance> notPreServers = new ArrayList<>(4);

        for (ServiceInstance instance : serviceInstances) {
            NacosServiceInstance nacosServiceInstance = (NacosServiceInstance) instance;
            Map<String, String> metadata = nacosServiceInstance.getMetadata();
            // 是否开启了预发模式
            if (this.isPreServer(metadata)) {
                preServers.add(instance);
            } else if (this.isGrayServer(metadata)) {
                grayServers.add(instance);
            } else {
                notPreServers.add(instance);
            }
            notPreServers.addAll(grayServers);
        }
        // 如果没有开启预发布服务和灰度发布，直接用默认的方式
        if (preServers.isEmpty() && grayServers.isEmpty()) {
            return getInstance(serviceId, clientIp, serviceInstances);
        }
        // 如果是从预发布域名访问过来，则认为是预发布请求，选出预发服务器
        if (this.isRequestFromPreDomain(request)) {
            return getInstance(serviceId, clientIp, preServers);
        }
        // 如果是灰度请求，则认为是灰度用户，选出灰度服务器
        if (this.isRequestGrayServer(request)) {
            return getInstance(serviceId, clientIp, grayServers);
        }
        // 到这里说明不能访问预发/灰度服务器，则需要路由到非预发服务器
        // 注意：这里允许走灰度服务器，如果不允许走，注释notPreServers.addAll(grayServers);这行
        return getInstance(serviceId, clientIp, notPreServers);
    }


    private ServiceInstance getInstance(String serviceId, String clientIp, List<ServiceInstance> instances) {
        if (instances.isEmpty()) {
            if (log.isWarnEnabled()) {
                log.warn("没有可供服务的服务器: " + serviceId);
            }
            return new EmptyResponse().getServer();
        }

            if (StringUtils.isNotEmpty(clientIp)) {
            instances.removeIf(instance -> !Objects.equals(clientIp, instance.getHost()));
            return LoadBalanceUtil.chooseByRoundRobin(serviceId + ":" + clientIp, instances);
        }
        // todo 写死 ，host 不是 192.168.2.212 ,192.168.2.252 ,192.168.2.253
        //  或者不是192.168.0.x 的服务全部剔除
        instances.removeIf(instance -> {
            String host = instance.getHost();
            return !(host.equals("192.168.2.212")
                    || host.equals("192.168.2.252")
                    || host.equals("192.168.2.253")
                    || host.matches("192\\.168\\.0\\..*"));

        });
        if (instances.isEmpty()) {
            if (log.isWarnEnabled()) {
                log.warn("没有可供服务的服务器: " + serviceId);
            }
            return new EmptyResponse().getServer();
        }
        return instances.size() == 1 ? instances.get(0) : LoadBalanceUtil.chooseByRoundRobin(serviceId, instances);
    }


    /**
     * 是否是预发布服务器
     *
     * @param metadata metadata
     * @return true：是
     */
    private boolean isPreServer(Map<String, String> metadata) {
        return Objects.equals(metadata.get(SopConstants.METADATA_ENV_KEY), SopConstants.METADATA_ENV_PRE_VALUE);
    }

    /**
     * 是否是灰度发布服务器
     *
     * @param metadata metadata
     * @return true：是
     */
    private boolean isGrayServer(Map<String, String> metadata) {
        return Objects.equals(metadata.get(SopConstants.METADATA_ENV_KEY), SopConstants.METADATA_ENV_GRAY_VALUE);
    }

    @Override
    public ApiParam getApiParam(ServerWebExchange exchange) {
        return ServerWebExchangeUtil.getApiParam(exchange);
    }

    @Override
    public String getHost(ServerWebExchange exchange) {
        return exchange.getRequest().getURI().getHost();
    }
}
